/*****************************************************************************
*
*    RegisterNativeEvent v1.1.1.5
*       by Bannar
*
*    Storage of trigger handles for native events.
*
******************************************************************************
*
*    Optional requirements:
*
*       Table by Bribe
*          hiveworkshop.com/threads/snippet-new-table.188084/
*
******************************************************************************
*
*    Important:
*
*       Avoid using TriggerSleepAction within functions registered.
*       Destroy native event trigger on your own responsibility.
*
******************************************************************************
*
*    Core:
*
*       function IsNativeEventRegistered takes integer whichIndex, integer whichEvent returns boolean
*          Whether index whichIndex has already been attached to event whichEvent.
*
*       function RegisterNativeEventTrigger takes integer whichIndex, integer eventId returns boolean
*          Registers whichIndex within whichEvent scope and assigns new trigger handle for it.
*
*       function GetIndexNativeEventTrigger takes integer whichIndex, integer whichEvent returns trigger
*          Retrieves trigger handle for event whichEvent specific to provided index whichIndex.
*
*       function GetNativeEventTrigger takes integer whichEvent returns trigger
*          Retrieves trigger handle for event whichEvent.
*
*
*    Custom events:
*
*       function CreateNativeEvent takes nothing returns integer
*          Returns unique id for new event and registers it with RegisterNativeEvent.
*
*       function RegisterIndexNativeEvent takes integer whichIndex, integer whichEvent, code func returns triggercondition
*          Registers new event handler func for event whichEvent specific to index whichIndex.
*
*       function RegisterNativeEvent takes integer whichEvent, code func returns triggercondition
*          Registers new event handler func for specified event whichEvent.
*
*       function UnregisterNativeEventHandler takes integer whichEvent, triggercondition handler returns nothing
*          Unregisters specified event handler for event whichEvent. Requires Warcraft 1.30.4+.
*
*****************************************************************************/
library RegisterNativeEvent uses optional Table

globals
    private integer eventIndex = 500 // 0-499 reserved for Blizzard native events

    /**
     *  For use with RegisterGameEvent
     */
    constant integer gameevent_VICTORY         = 0
    constant integer gameevent_END_LEVEL       = 1
    constant integer gameevent_VARIABLE_LIMIT  = 2
    constant integer gameevent_STATE_LIMIT     = 3
    constant integer gameevent_TIMER_EXPIRED   = 4
    constant integer gameevent_ENTER_REGION    = 5
    constant integer gameevent_LEAVE_REGION    = 6
    constant integer gameevent_TRACKABLE_HIT   = 7
    constant integer gameevent_TRACKABLE_TRACK = 8
    constant integer gameevent_SHOW_SKILL      = 9
    constant integer gameevent_BUILD_SUBMENU   = 10
    /**
     *  For use with RegisterPlayerEvent
     */
    constant integer playerevent_STATE_LIMIT      = 11
    constant integer playerevent_ALLIANCE_CHANGED = 12
    constant integer playerevent_DEFEAT           = 13
    constant integer playerevent_VICTORY          = 14
    constant integer playerevent_LEAVE            = 15
    constant integer playerevent_CHAT             = 16
    constant integer playerevent_END_CINEMATIC    = 17
    /**
     *  For use with RegisterPlayerUnitEvent
     */
    constant integer playerunitevent_ATTACKED            = 18
    constant integer playerunitevent_RESCUED             = 19
    constant integer playerunitevent_DEATH               = 20
    constant integer playerunitevent_DECAY               = 21
    constant integer playerunitevent_DETECTED            = 22
    constant integer playerunitevent_HIDDEN              = 23
    constant integer playerunitevent_SELECTED            = 24
    constant integer playerunitevent_DESELECTED          = 25
    constant integer playerunitevent_CONSTRUCT_START     = 26
    constant integer playerunitevent_CONSTRUCT_CANCEL    = 27
    constant integer playerunitevent_CONSTRUCT_FINISH    = 28
    constant integer playerunitevent_UPGRADE_START       = 29
    constant integer playerunitevent_UPGRADE_CANCEL      = 30
    constant integer playerunitevent_UPGRADE_FINISH      = 31
    constant integer playerunitevent_TRAIN_START         = 32
    constant integer playerunitevent_TRAIN_CANCEL        = 33
    constant integer playerunitevent_TRAIN_FINISH        = 34
    constant integer playerunitevent_RESEARCH_START      = 35
    constant integer playerunitevent_RESEARCH_CANCEL     = 36
    constant integer playerunitevent_RESEARCH_FINISH     = 37
    constant integer playerunitevent_ISSUED_ORDER        = 38
    constant integer playerunitevent_ISSUED_POINT_ORDER  = 39
    constant integer playerunitevent_ISSUED_TARGET_ORDER = 40
    constant integer playerunitevent_ISSUED_UNIT_ORDER   = 40 // for compat
    constant integer playerunitevent_HERO_LEVEL          = 41
    constant integer playerunitevent_HERO_SKILL          = 42
    constant integer playerunitevent_HERO_REVIVABLE      = 43
    constant integer playerunitevent_HERO_REVIVE_START   = 44
    constant integer playerunitevent_HERO_REVIVE_CANCEL  = 45
    constant integer playerunitevent_HERO_REVIVE_FINISH  = 46
    constant integer playerunitevent_SUMMON              = 47
    constant integer playerunitevent_DROP_ITEM           = 48
    constant integer playerunitevent_PICKUP_ITEM         = 49
    constant integer playerunitevent_USE_ITEM            = 50
    constant integer playerunitevent_LOADED              = 51
    /**
     *  For use with RegisterUnitEvent
     */
    constant integer unitevent_DAMAGED             = 52
    constant integer unitevent_DEATH               = 53
    constant integer unitevent_DECAY               = 54
    constant integer unitevent_DETECTED            = 55
    constant integer unitevent_HIDDEN              = 56
    constant integer unitevent_SELECTED            = 57
    constant integer unitevent_DESELECTED          = 58
    constant integer unitevent_STATE_LIMIT         = 59
    constant integer unitevent_ACQUIRED_TARGET     = 60
    constant integer unitevent_TARGET_IN_RANGE     = 61
    constant integer unitevent_ATTACKED            = 62
    constant integer unitevent_RESCUED             = 63
    constant integer unitevent_CONSTRUCT_CANCEL    = 64
    constant integer unitevent_CONSTRUCT_FINISH    = 65
    constant integer unitevent_UPGRADE_START       = 66
    constant integer unitevent_UPGRADE_CANCEL      = 67
    constant integer unitevent_UPGRADE_FINISH      = 68
    constant integer unitevent_TRAIN_START         = 69
    constant integer unitevent_TRAIN_CANCEL        = 70
    constant integer unitevent_TRAIN_FINISH        = 71
    constant integer unitevent_RESEARCH_START      = 72
    constant integer unitevent_RESEARCH_CANCEL     = 73
    constant integer unitevent_RESEARCH_FINISH     = 74
    constant integer unitevent_ISSUED_ORDER        = 75
    constant integer unitevent_ISSUED_POINT_ORDER  = 76
    constant integer unitevent_ISSUED_TARGET_ORDER = 77
    constant integer unitevent_HERO_LEVEL          = 78
    constant integer unitevent_HERO_SKILL          = 79
    constant integer unitevent_HERO_REVIVABLE      = 80
    constant integer unitevent_HERO_REVIVE_START   = 81
    constant integer unitevent_HERO_REVIVE_CANCEL  = 82
    constant integer unitevent_HERO_REVIVE_FINISH  = 83
    constant integer unitevent_SUMMON              = 84
    constant integer unitevent_DROP_ITEM           = 85
    constant integer unitevent_PICKUP_ITEM         = 86
    constant integer unitevent_USE_ITEM            = 87
    constant integer unitevent_LOADED              = 88
    /**
     *  For use with RegisterGameEvent
     */
    constant integer gameevent_LOADED                 = 256
    constant integer gameevent_TOURNAMENT_FINISH_SOON = 257
    constant integer gameevent_TOURNAMENT_FINISH_NOW  = 258
    constant integer gameevent_SAVE                   = 259
    /**
     *  For use with RegisterPlayerEvent
     */
    constant integer playerevent_ARROW_LEFT_DOWN  = 261
    constant integer playerevent_ARROW_LEFT_UP    = 262
    constant integer playerevent_ARROW_RIGHT_DOWN = 263
    constant integer playerevent_ARROW_RIGHT_UP   = 264
    constant integer playerevent_ARROW_DOWN_DOWN  = 265
    constant integer playerevent_ARROW_DOWN_UP    = 266
    constant integer playerevent_ARROW_UP_DOWN    = 267
    constant integer playerevent_ARROW_UP_UP      = 268
    constant integer playerevent_MOUSE_DOWN       = 269
    constant integer playerevent_MOUSE_UP         = 270
    constant integer playerevent_MOUSE_MOVE       = 271
    /**
     * For use with RegisterPlayerUnitEvent
     */
    constant integer playerunitevent_SELL          = 272
    constant integer playerunitevent_CHANGE_OWNER  = 273
    constant integer playerunitevent_SELL_ITEM     = 274
    constant integer playerunitevent_SPELL_CHANNEL = 275
    constant integer playerunitevent_SPELL_CAST    = 276
    constant integer playerunitevent_SPELL_EFFECT  = 277
    constant integer playerunitevent_SPELL_FINISH  = 278
    constant integer playerunitevent_SPELL_ENDCAST = 279
    constant integer playerunitevent_PAWN_ITEM     = 280
    /**
     *  For use with RegisterUnitEvent
     */
    constant integer unitevent_SELL          = 289
    constant integer unitevent_CHANGE_OWNER  = 290
    constant integer unitevent_SELL_ITEM     = 291
    constant integer unitevent_SPELL_CHANNEL = 292
    constant integer unitevent_SPELL_CAST    = 293
    constant integer unitevent_SPELL_EFFECT  = 294
    constant integer unitevent_SPELL_FINISH  = 295
    constant integer unitevent_SPELL_ENDCAST = 296
    constant integer unitevent_PAWN_ITEM     = 297
endglobals

private module NativeEventInit
    private static method onInit takes nothing returns nothing
static if LIBRARY_Table then
        set table = TableArray[0x2000]
endif
    endmethod
endmodule

private struct NativeEvent extends array
static if LIBRARY_Table then
    static TableArray table
else
    static hashtable table = InitHashtable()
endif
    implement NativeEventInit
endstruct

function IsNativeEventRegistered takes integer whichIndex, integer whichEvent returns boolean
static if LIBRARY_Table then
    return NativeEvent.table[whichEvent].trigger.has(whichIndex)
else
    return HaveSavedHandle(NativeEvent.table, whichEvent, whichIndex)
endif
endfunction

function RegisterNativeEventTrigger takes integer whichIndex, integer whichEvent returns boolean
    if not IsNativeEventRegistered(whichIndex, whichEvent) then
static if LIBRARY_Table then
        set NativeEvent.table[whichEvent].trigger[whichIndex] = CreateTrigger()
else
        call SaveTriggerHandle(NativeEvent.table, whichEvent, whichIndex, CreateTrigger())
endif
        return true
    endif
    return false
endfunction

function GetIndexNativeEventTrigger takes integer whichIndex, integer whichEvent returns trigger
static if LIBRARY_Table then
    return NativeEvent.table[whichEvent].trigger[whichIndex]
else
    return LoadTriggerHandle(NativeEvent.table, whichEvent, whichIndex)
endif
endfunction

function GetNativeEventTrigger takes integer whichEvent returns trigger
    return GetIndexNativeEventTrigger(bj_MAX_PLAYER_SLOTS, whichEvent)
endfunction

function CreateNativeEvent takes nothing returns integer
    local integer eventId = eventIndex
    call RegisterNativeEventTrigger(bj_MAX_PLAYER_SLOTS, eventId)
    set eventIndex = eventIndex + 1
    return eventId
endfunction

function RegisterIndexNativeEvent takes integer whichIndex, integer whichEvent, code func returns triggercondition
    call RegisterNativeEventTrigger(whichIndex, whichEvent)
    return TriggerAddCondition(GetIndexNativeEventTrigger(whichIndex, whichEvent), Condition(func))
endfunction

function RegisterNativeEvent takes integer whichEvent, code func returns triggercondition
    return RegisterIndexNativeEvent(bj_MAX_PLAYER_SLOTS, whichEvent, func)
endfunction

function UnregisterNativeEventHandler takes integer whichEvent, triggercondition handler returns nothing
    call TriggerRemoveCondition(GetNativeEventTrigger(whichEvent), handler)
endfunction

endlibrary